package pe.com.empresa.utiles;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;

import pe.com.empresa.utiles.IServiceHelper;
import pe.com.empresa.utiles.Criteria;

public class ServiceHelper implements IServiceHelper {

	protected SqlSession session;
	protected SqlSessionFactory sessionFactory;

	@Override
	public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {
		this.sessionFactory = sqlSessionFactory;
	}

	@Override
	public void actualizar(Object object) throws Exception {
		this.updateByPrimaryKey(object);
	}

	@Override
	public void insertar(Object object) throws Exception {
		this.insert(object);
	}

	@SuppressWarnings("rawtypes")
	@Override
	public void eliminar(Class mapperClass, Object obj) throws Exception {
		invokeCRUDOperation(mapperClass, obj, "deleteByPrimaryKey");
	}

	@Override
	public void commit() throws SQLException {

		if (session != null) {
			System.out.println("commit");
			session.getConnection().commit();
		}
	}

	@Override
	public void rollback() throws SQLException {
		if (session != null) {
			System.out.println("rollback");
			session.rollback();
		}
	}

	@SuppressWarnings("rawtypes")
	private void insert(Class mapperClass, Object obj) throws Exception {
		invokeCRUDOperation(mapperClass, obj, "insert");
	}

	
	private void insert(Object obj) throws Exception {
		insert(findMapperClass(obj), obj);
	}

	private void updateByPrimaryKey(Object obj) throws Exception {
		updateByPrimaryKey(findMapperClass(obj), obj);
	}

	@SuppressWarnings("rawtypes")
	private void updateByPrimaryKey(Class mapperClass, Object obj)
			throws Exception {
		invokeCRUDOperation(mapperClass, obj, "updateByPrimaryKey");
	}

	@SuppressWarnings("rawtypes")
	public Object selectByPrimaryKey(Class mapperClass, Integer id) {
		String operation = mapperClass.getName() + ".selectByPrimaryKey";
		System.out.println(operation);
		List list = session.selectList(operation, id);
		if (list == null) {
			return null;
		} else {
			return list.get(0);
		}
	}
	@Override
	@SuppressWarnings("rawtypes")
	public Object selectByPrimaryKey(Class mapperClass, String id) {
		String operation = mapperClass.getName() + ".selectByPrimaryKey";
		System.out.println(operation);
		List list = session.selectList(operation, id);
		if (list == null) {
			return null;
		} else {
			return list.get(0);
		}
	}

	@SuppressWarnings("rawtypes")
	private Class findMapperClass(Object obj) throws ClassNotFoundException {
		Class c;
		String className = obj.getClass().getName();
		className = className.replaceFirst("dominio", "dao") + "Mapper";
		System.out.println(className);
		c = Class.forName(className);
		return c;
	}

	@SuppressWarnings({ "rawtypes", "unchecked" })
	private void invokeCRUDOperation(Class mapperClass, Object obj,
			String operation) throws Exception {
		if (session != null) {
			for (Method method : mapperClass.getMethods()) {
				if (method.getName().equals(operation)) {
					Object mapper = session.getMapper(mapperClass);
					Object parameters[] = { obj };
					try {
						method.invoke(mapper, parameters);
						System.out.println(operation);
					} catch (IllegalAccessException e) {
						e.printStackTrace();
					} catch (InvocationTargetException e) {
						e.printStackTrace();
					}
					break;
				}
			}
		}
	}
	@Override
	@SuppressWarnings("rawtypes")
	public List selectByCriteria(String nomQuery, Criteria criteria) {
		String operation = "pe.com.empresa.datos.dao." + nomQuery + "Mapper"
				+ "." + this.getNombreMetodoLower(nomQuery);
		System.out.println("Operacion: " + operation);
		List result = session.selectList(operation, criteria);
		if (result == null) {
			result = new ArrayList();
		}
		return result;
	}
	@Override
	@SuppressWarnings("rawtypes")
	public List selectByCriteria(String nomMapper,String nomQuery, Criteria criteria) {
		String operation = "pe.com.empresa.datos.dao." + nomMapper + "Mapper"
				+ "." + this.getNombreMetodoLower(nomQuery);
		System.out.println("Operacion: " + operation);
		List result = session.selectList(operation, criteria);
		if (result == null) {
			result = new ArrayList();
		}
		return result;
	}

	private String getNombreMetodoLower(String nombreMetodo) {
		return nombreMetodo.substring(0, 1).toLowerCase()
				+ nombreMetodo.substring(1, nombreMetodo.length());
	}

	@Override
	public SqlSession getSession() {
		return this.session;
	}

	@Override
	public void openSession() throws SQLException {
		this.session = sessionFactory.openSession();
	}

	@Override
	public void closeSession() throws SQLException {
		this.session.close();
	}

}
